"""
文件名: auth.py
描述: 用户认证API路由

本模块包含以下主要功能：
1. OAuth授权URL生成
2. OAuth回调处理
3. 用户登录和登出
4. 令牌刷新
5. 用户信息获取

依赖模块:
   - fastapi: Web框架路由
   - services: 认证服务
   - models: 数据模型

使用示例:
   >>> GET /auth/login - 获取授权URL
   >>> GET /auth/callback?code=xxx&state=xxx - 处理OAuth回调
   >>> POST /auth/refresh - 刷新访问令牌
   >>> POST /auth/logout - 用户登出

注意事项:
   - OAuth流程要验证state参数
   - 令牌要设置合理过期时间
   - 登出要清理会话数据
   - 错误信息要用户友好

作者: AI助手
创建日期: 2024-06-27
最后修改: 2024-06-27
版本: 1.0.0
"""

from typing import Dict, Any
import uuid

from fastapi import APIRouter, Depends, HTTPException, status, Query, Request, Response
from fastapi.responses import RedirectResponse
from pydantic import BaseModel

from src.api.dependencies import get_auth_service, get_current_user, get_rate_limit_info
from src.core.logger import get_logger
from src.models.user import UserInDB
from src.services.auth_service import AuthService
from src.utils.exceptions import (
    AuthenticationException,
    ValidationException,
    InvalidTokenException,
)

logger = get_logger(__name__)

router = APIRouter()


class TokenResponse(BaseModel):
    """令牌响应模型"""
    access_token: str
    refresh_token: str
    token_type: str = "bearer"
    expires_in: int


class RefreshTokenRequest(BaseModel):
    """刷新令牌请求模型"""
    refresh_token: str


class AuthURLResponse(BaseModel):
    """授权URL响应模型"""
    authorization_url: str
    state: str


@router.get("/login", response_model=AuthURLResponse, summary="获取OAuth授权URL")
async def get_authorization_url(
    request: Request,
    auth_service: AuthService = Depends(get_auth_service),
    rate_limit: Dict[str, str] = Depends(get_rate_limit_info),
) -> AuthURLResponse:
    """
    获取Google OAuth授权URL
    
    此端点生成Google OAuth 2.0授权URL，用户需要访问此URL进行授权。
    授权成功后，Google会重定向到回调URL。
    
    Returns:
        AuthURLResponse: 包含授权URL和状态参数的响应
    """
    try:
        authorization_url, state = await auth_service.get_authorization_url()
        
        logger.info(
            f"生成OAuth授权URL成功", 
            client_ip=rate_limit["client_ip"],
            state=state
        )
        
        return AuthURLResponse(
            authorization_url=authorization_url,
            state=state
        )
        
    except Exception as e:
        logger.error(f"生成OAuth授权URL失败: {e}", client_ip=rate_limit["client_ip"])
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="生成授权URL失败，请稍后重试"
        )


@router.get("/callback", response_model=TokenResponse, summary="OAuth回调处理")
async def oauth_callback(
    code: str = Query(..., description="OAuth授权码"),
    state: str = Query(..., description="状态参数"),
    error: str = Query(None, description="错误信息"),
    auth_service: AuthService = Depends(get_auth_service),
    rate_limit: Dict[str, str] = Depends(get_rate_limit_info),
) -> TokenResponse:
    """
    处理Google OAuth回调
    
    此端点处理Google OAuth授权回调，验证授权码并创建用户会话。
    
    Args:
        code: Google返回的授权码
        state: 状态参数，用于防CSRF攻击
        error: 错误信息（如果授权失败）
        
    Returns:
        TokenResponse: 包含访问令牌和刷新令牌的响应
    """
    # 检查是否有错误
    if error:
        logger.warning(f"OAuth授权失败: {error}", client_ip=rate_limit["client_ip"])
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"授权失败: {error}"
        )
    
    try:
        # 使用授权码进行认证
        user = await auth_service.authenticate_with_code(code, state)
        
        # 创建访问令牌和刷新令牌
        access_token = await auth_service.create_access_token(str(user.id))
        refresh_token = await auth_service.create_refresh_token(str(user.id))
        
        logger.info(
            f"OAuth认证成功", 
            user_id=str(user.id),
            email=user.email,
            client_ip=rate_limit["client_ip"]
        )
        
        return TokenResponse(
            access_token=access_token,
            refresh_token=refresh_token,
            expires_in=3600,  # 1小时
        )
        
    except ValidationException as e:
        logger.warning(f"OAuth回调参数验证失败: {e}", client_ip=rate_limit["client_ip"])
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e)
        )
    except AuthenticationException as e:
        logger.error(f"OAuth认证失败: {e}", client_ip=rate_limit["client_ip"])
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=str(e)
        )
    except Exception as e:
        logger.error(f"OAuth回调处理失败: {e}", client_ip=rate_limit["client_ip"])
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="认证处理失败，请稍后重试"
        )


@router.post("/refresh", response_model=TokenResponse, summary="刷新访问令牌")
async def refresh_access_token(
    request: RefreshTokenRequest,
    auth_service: AuthService = Depends(get_auth_service),
    rate_limit: Dict[str, str] = Depends(get_rate_limit_info),
) -> TokenResponse:
    """
    刷新访问令牌
    
    当访问令牌过期时，可以使用刷新令牌获取新的访问令牌。
    
    Args:
        request: 刷新令牌请求
        
    Returns:
        TokenResponse: 新的访问令牌和刷新令牌
    """
    try:
        # 刷新令牌
        new_access_token, new_refresh_token = await auth_service.refresh_access_token(
            request.refresh_token
        )
        
        logger.info(f"令牌刷新成功", client_ip=rate_limit["client_ip"])
        
        return TokenResponse(
            access_token=new_access_token,
            refresh_token=new_refresh_token,
            expires_in=3600,
        )
        
    except InvalidTokenException as e:
        logger.warning(f"刷新令牌无效: {e}", client_ip=rate_limit["client_ip"])
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="刷新令牌无效或已过期"
        )
    except Exception as e:
        logger.error(f"令牌刷新失败: {e}", client_ip=rate_limit["client_ip"])
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="令牌刷新失败，请重新登录"
        )


@router.post("/logout", summary="用户登出")
async def logout(
    current_user: UserInDB = Depends(get_current_user),
    auth_service: AuthService = Depends(get_auth_service),
    rate_limit: Dict[str, str] = Depends(get_rate_limit_info),
) -> Dict[str, str]:
    """
    用户登出
    
    清除用户会话数据，使访问令牌失效。
    
    Returns:
        Dict[str, str]: 登出结果
    """
    try:
        await auth_service.logout(str(current_user.id))
        
        logger.info(
            f"用户登出成功", 
            user_id=str(current_user.id),
            client_ip=rate_limit["client_ip"]
        )
        
        return {"message": "登出成功"}
        
    except Exception as e:
        logger.error(
            f"用户登出失败: {e}", 
            user_id=str(current_user.id),
            client_ip=rate_limit["client_ip"]
        )
        # 登出失败也返回成功，避免暴露系统错误
        return {"message": "登出成功"}


@router.get("/me", response_model=UserInDB, summary="获取当前用户信息")
async def get_current_user_info(
    current_user: UserInDB = Depends(get_current_user),
) -> UserInDB:
    """
    获取当前认证用户的详细信息
    
    Returns:
        UserInDB: 当前用户信息
    """
    return current_user


@router.get("/status", summary="检查认证状态")
async def check_auth_status(
    current_user: UserInDB = Depends(get_current_user),
) -> Dict[str, Any]:
    """
    检查用户认证状态
    
    Returns:
        Dict[str, Any]: 认证状态信息
    """
    return {
        "authenticated": True,
        "user_id": str(current_user.id),
        "email": current_user.email,
        "is_active": current_user.is_active,
        "is_premium": current_user.is_premium,
        "last_login": current_user.last_login_at,
    }